package repository

import (
	"bytes"
	"github.com/jinzhu/gorm"
	"mall-go/common"
	"mall-go/dto"
	"mall-go/model"
	"mall-go/util"
	"mall-go/vo"
	"time"
)

type MallOrderRepo struct {
	DB *gorm.DB
}

func NewMallOrderRepo() MallOrderRepo {
	db := common.GetDB()
	return MallOrderRepo{DB: db}
}
func (receiver MallOrderRepo) GetOrderDetailByOrderNo(orderNo string, userId uint) vo.NewBeeMallOrderDetailVO {
	//根据订单编号查询数据
	var order model.Order
	receiver.DB.Where("order_no = ? and is_deleted = 0", orderNo).First(&order)
	if order.OrderId == 0 {
		panic("数据不存在")
	}
	if userId != order.UserID {
		panic("非法操作！")
	}
	//根据订单ID查询数据
	var orderItems []model.OrderItem
	receiver.DB.Where("order_id = ?", order.OrderId).Find(&orderItems)
	//获取订单项数据
	if len(orderItems) != 0 {
		//拷贝数据给vo
		var newBeeMallOrderItemVOS []vo.NewBeeMallOrderItemVO
		for _, item := range orderItems {
			newBeeMallOrderItemVO := vo.NewBeeMallOrderItemVO{
				GoodsId:       int(item.GoodsId),
				GoodsCount:    int(item.GoodsCount),
				GoodsName:     item.GoodsName,
				GoodsCoverImg: item.GoodsCoverImg,
			}
			newBeeMallOrderItemVOS = append(newBeeMallOrderItemVOS, newBeeMallOrderItemVO)
		}
		newBeeMallOrderDetailVO := vo.NewBeeMallOrderDetailVO{
			OrderNo:     order.OrderNo,
			TotalPrice:  order.TotalPrice,
			PayStatus:   byte(order.PayStatus),
			PayType:     order.PayType,
			OrderStatus: order.OrderStatus,
		}
		//通过订单条件筛选器筛选状态
		newBeeMallOrderDetailVO.OrderStatusString = util.GetNewBeeMallOrderStatusEnumByStatus(newBeeMallOrderDetailVO.OrderStatus)
		//支付条件筛选器
		newBeeMallOrderDetailVO.PayTypeString = util.GetPayTypeEnumByType(newBeeMallOrderDetailVO.PayType)
		newBeeMallOrderDetailVO.NewBeeMallOrderItemVOS = newBeeMallOrderItemVOS
		return newBeeMallOrderDetailVO
	}
	panic("订单项异常")
}

func (receiver MallOrderRepo) GetCartItemsForSettle(cartItemIds []int, userId uint) []vo.NewBeeMallShoppingCartItemVO {
	cartRepo := NewShoppingCartRepo()
	if len(cartItemIds) == 0 {
		panic("购物项不能为空")
	}
	var newBeeMallShoppingCartItems []model.ShoppingCart
	receiver.DB.Where("cart_item_id in ("+util.Convert(cartItemIds)+")").Where("user_id = ? and is_deleted = 0", userId).Find(&newBeeMallShoppingCartItems)
	if len(newBeeMallShoppingCartItems) == 0 {
		panic("购物项不能为空")
	}
	if len(newBeeMallShoppingCartItems) != len(cartItemIds) {
		panic("参数异常")
	}
	//将购物车转换为出参数据
	return cartRepo.getNewBeeMallShoppingCartItemVOS(newBeeMallShoppingCartItems)
}

// GetMyOrders 获取订单列表
func (receiver MallOrderRepo) GetMyOrders(orderPageDTO dto.OrderPageDTO) vo.OrderPageResult {
	//获取订单总数
	total := receiver.getTotalNewBeeMallOrders(orderPageDTO)
	orders := receiver.findNewBeeMallOrderList(orderPageDTO)
	if total > 0 {
		//将实体数据转换成vo
		var orderVOS []vo.NewBeeMallOrderListVO
		for _, order := range orders {
			orderVO := vo.NewBeeMallOrderListVO{
				OrderId:     int(order.OrderId),
				OrderNo:     order.OrderNo,
				TotalPrice:  order.TotalPrice,
				PayType:     order.PayType,
				OrderStatus: order.OrderStatus,
			}
			orderVOS = append(orderVOS, orderVO)
		}
		//设置订单状态为中文显示
		for i, orderVO := range orderVOS {
			orderVOS[i].OrderStatusString = util.GetNewBeeMallOrderStatusEnumByStatus(orderVO.OrderStatus)
		}
		//收集订单id集合
		var orderIds []uint
		for _, order := range orders {
			orderIds = append(orderIds, order.OrderId)
		}
		if len(orderIds) > 0 {
			//根据订单id集合查询订单信息
			var orderItems []model.OrderItem
			receiver.DB.Where("order_id in (" + util.Convert(orderIds) + ")").Find(&orderItems)
			//做一个订单id和订单的映射
			//todo 插入不进去值
			itemByOrderIdMap := make(map[int][]model.OrderItem)
			for _, item := range orderItems {
				itemByOrderIdMap[int(item.OrderId)] = append(itemByOrderIdMap[int(item.OrderId)], item)
			}
			for i, orderVO := range orderVOS {
				//封装每个订单列表对象的订单项数据
				if orderItemListTemp, ok := itemByOrderIdMap[orderVO.OrderId]; ok {
					//拿到后将该集合转换成vo
					var newBeeMallOrderItemVOS []vo.NewBeeMallOrderItemVO
					for _, item := range orderItemListTemp {
						newBeeMallOrderItemVO := vo.NewBeeMallOrderItemVO{
							GoodsId:       int(item.GoodsId),
							GoodsCount:    int(item.GoodsCount),
							GoodsName:     item.GoodsName,
							GoodsCoverImg: item.GoodsCoverImg,
							SellingPrice:  int(item.SellingPrice),
						}
						newBeeMallOrderItemVOS = append(newBeeMallOrderItemVOS, newBeeMallOrderItemVO)
						orderVOS[i].CreateTime = item.CreateTime
						orderVOS[i].NewBeeMallOrderItemVOS = newBeeMallOrderItemVOS
					}
				}
			}
		}
		return vo.OrderPageResult{
			PageResult: vo.PageResult{
				TotalCount: total,
				PageSize:   orderPageDTO.Limit,
				TotalPage:  total / orderPageDTO.Limit,
				CurrPage:   orderPageDTO.Page,
			},
			List: orderVOS,
		}
	}
	return vo.OrderPageResult{
		PageResult: vo.PageResult{},
		List:       nil,
	}
}

func (receiver MallOrderRepo) GetMallUserAddressById(addressId int) model.UserAddress {
	var userAddress model.UserAddress
	receiver.DB.Where("address_id = ? and is_deleted = 0", addressId).First(&userAddress)
	if userAddress.AddressID == 0 {
		panic("数据不存在")
	}
	return userAddress
}

// SaveOrder 保存订单
func (receiver MallOrderRepo) SaveOrder(userId uint, address model.UserAddress, myShoppingCartItems []vo.NewBeeMallShoppingCartItemVO) string {
	//收集购物项id集合和商品id集合
	var itemIdList []int
	var goodsIds []int
	for _, item := range myShoppingCartItems {
		itemIdList = append(itemIdList, item.CartItemId)
		goodsIds = append(goodsIds, item.GoodsId)
	}
	//根据商品id集合查询商品数据
	var newBeeMallGoods []model.GoodsInfo
	goodsRepo := NewMallGoodsRepo()
	goodsRepo.DB.Debug().Where("goods_id in (" + util.Convert(goodsIds) + ")").Order("field(goods_id," + util.Convert(goodsIds) + ")").Find(&newBeeMallGoods)
	//检查是否包含下架商品
	for _, good := range newBeeMallGoods {
		if good.GoodsSellStatus != 0 {
			//这种是将下架商品剔除，然后生成订单
			//newBeeMallGoods = append(newBeeMallGoods[:i], newBeeMallGoods[i+1:]...)
			panic(good.GoodsName + "已下架，无法生成订单")
		}
	}
	newBeeMallGoodsMap := make(map[int]model.GoodsInfo)
	for _, good := range newBeeMallGoods {
		newBeeMallGoodsMap[good.GoodsId] = good
	}
	//判断商品库存
	for _, item := range myShoppingCartItems {
		//查出的商品中不存在购物车中的这条关联商品数据，直接返回错误提醒
		if _, ok := newBeeMallGoodsMap[item.GoodsId]; !ok {
			panic("购物车数据异常")
		}
		//存在数量大于库存的情况，直接返回错误提醒
		//todo 后期这里可能需要加锁
		if item.GoodsCount > newBeeMallGoodsMap[item.GoodsId].StockNum {
			panic("库存不足")
		}
	}
	//删除购物项
	if len(itemIdList) != 0 && len(goodsIds) != 0 && len(newBeeMallGoods) != 0 {
		//批量删除
		err := receiver.DB.Debug().Model(&model.ShoppingCart{}).Where("cart_item_id in ("+util.Convert(itemIdList)+")").Update("is_deleted", 1).Error
		if err == nil {
			//将数据拷贝给vo
			var stockNumDTOS []dto.StockNumDTO
			for _, item := range myShoppingCartItems {
				stockNumDTO := dto.StockNumDTO{
					GoodsId:    item.GoodsId,
					GoodsCount: item.GoodsCount,
				}
				stockNumDTOS = append(stockNumDTOS, stockNumDTO)
			}
			for _, numDTO := range stockNumDTOS {
				err := receiver.DB.Model(&model.GoodsInfo{}).Update("stock_num = stock_num - ?", numDTO.GoodsCount).
					Where("goods_id = ? and stock_num >= ? and goods_sell_status = 0", numDTO.GoodsId, numDTO.GoodsCount).Error
				if err != nil {
					panic("库存不足")
				}
			}
			//生成订单号4位
			orderNo := util.RandomString(4)
			priceTotal := 0
			//保存订单
			var saveOrder model.Order
			saveOrder.OrderNo = orderNo
			saveOrder.UserID = userId
			//总价
			for _, item := range myShoppingCartItems {
				priceTotal += item.SellingPrice * item.GoodsCount
			}
			if priceTotal < 1 {
				panic("订单价格异常")
			}
			saveOrder.TotalPrice = priceTotal
			saveOrder.ExtraInfo = ""
			//生成订单项并保存订单记录
			err := receiver.DB.Debug().Create(&saveOrder).Error
			if err == nil {
				//生成订单收货地址快照，并保存至数据库
				newBeeMallOrderAddress := model.OrderAddress{
					UserName:      address.UserName,
					UserPhone:     address.UserPhone,
					ProvinceName:  address.ProvinceName,
					CityName:      address.CityName,
					RegionName:    address.RegionName,
					DetailAddress: address.DetailAddress,
				}
				newBeeMallOrderAddress.OrderId = saveOrder.OrderId
				//生成所有的订单项快照，并保存至数据库
				newBeeMallOrderItems := []model.OrderItem{}
				for _, item := range myShoppingCartItems {
					newBeeMallOrderItem := model.OrderItem{
						OrderId:       saveOrder.OrderId,
						GoodsId:       uint(item.GoodsId),
						GoodsName:     item.GoodsName,
						GoodsCoverImg: item.GoodsCoverImg,
						SellingPrice:  uint(item.SellingPrice),
						GoodsCount:    uint(item.GoodsCount),
					}
					newBeeMallOrderItems = append(newBeeMallOrderItems, newBeeMallOrderItem)
				}
				//先插入订单快照中
				itemRepo := NewMallOrderItemRepo()
				addressRepo := NewMallOrderAddressRepo()
				//这个版本的gorm比较旧，不提供批量插入，所以这里写个循环插入
				for _, item := range newBeeMallOrderItems {
					if err := itemRepo.DB.Create(&item).Error; err != nil {
						panic(err)
					}
				}
				if err2 := addressRepo.DB.Debug().Create(&newBeeMallOrderAddress).Error; err2 == nil {
					//将订单号返回
					return orderNo
				}
				panic("订单价格异常")
			}
			panic(err)
		}
		panic("database error")
	}
	panic("购物车数据异常")
}

func (receiver MallOrderRepo) CancelOrder(orderNo string, userId uint) string {
	//根据订单编号查询数据
	var order model.Order
	receiver.DB.Where("order_no = ? and is_deleted = 0", orderNo).First(&order)
	if order.OrderId != 0 {
		if order.UserID != userId {
			panic("非法操作")
		}
		//订单状态判断
		if order.OrderStatus == 4 ||
			order.OrderStatus == -1 ||
			order.OrderStatus == -2 ||
			order.OrderStatus == -3 {
			return "订单状态异常"
		}
		//关闭订单操作
		if err := receiver.DB.Model(&model.Order{OrderId: order.OrderId}).Update(model.Order{OrderStatus: -1, UpdateTime: model.Time(time.Now())}).Error; err != nil {
			return "订单关闭异常"
		} else {
			return "Success"
		}
	}
	return "订单找不到"
}

func (receiver MallOrderRepo) FinishOrder(orderNo string, userId uint) string {
	//根据订单编号查询数据
	var order model.Order
	receiver.DB.Where("order_no = ? and is_deleted = 0", orderNo).First(&order)
	if order.OrderId != 0 {
		if order.UserID != userId {
			panic("非法操作")
		}
		//订单状态判断 非出库状态下不进行修改操作
		if order.OrderStatus != 3 {
			return "订单状态异常"
		}

		//确认订单
		order.OrderStatus = 4
		order.UpdateTime = model.Time(time.Now())
		if err := receiver.DB.Model(&order).Update(order).Error; err != nil {
			return "订单确认异常"
		} else {
			return "Success"
		}
	}
	return "订单找不到"
}

func (receiver MallOrderRepo) PaySuccess(orderNo string, payType int) string {
	var order model.Order
	receiver.DB.Debug().Where("order_no = ? and is_deleted = 0", orderNo).First(&order)
	if order.OrderId != 0 {
		//订单状态判断 非待支付状态下不进行修改操作
		if order.OrderStatus != 0 {
			return "订单状态异常"
		}
		order.OrderStatus = 1
		order.PayType = payType
		order.PayStatus = 1
		order.PayTime = model.Time(time.Now())
		order.UpdateTime = model.Time(time.Now())
		if err := receiver.DB.Model(&order).Update(order).Error; err != nil {
			return "订单更新异常"
		} else {
			return "Success"
		}
	}
	return "数据不存在"
}

func (receiver MallOrderRepo) getTotalNewBeeMallOrders(pageDTO dto.OrderPageDTO) int {
	var total int
	tx := receiver.DB.Debug().Model(&model.Order{})
	if pageDTO.UserId != 0 {
		tx = tx.Where("user_id = ?", pageDTO.UserId)
	}
	if pageDTO.OrderStatus != 10 {
		tx = tx.Where("order_status = ?", pageDTO.OrderStatus)
	}
	tx.Count(&total)
	return total
}

func (receiver MallOrderRepo) findNewBeeMallOrderList(pageDTO dto.OrderPageDTO) []model.Order {
	var orders []model.Order
	tx := receiver.DB.Debug()
	if pageDTO.UserId != 0 {
		tx = tx.Where("user_id = ?", pageDTO.UserId)
	}
	if pageDTO.OrderStatus != 10 {
		tx = tx.Where("order_status = ?", pageDTO.OrderStatus)
	}
	tx.Order("create_time desc")
	if pageDTO.Start != 0 && pageDTO.Limit != 0 {
		tx = tx.Limit(pageDTO.Limit).Offset(pageDTO.Start)
	}
	tx.Find(&orders)
	return orders
}

func (receiver MallOrderRepo) GetNewBeeMallOrdersPage(pageDTO dto.OrderPageDTO) vo.AdminOrderPage {
	orders := receiver.findOrdersPage(pageDTO)
	total := receiver.findTotal(pageDTO)
	//封装分页数据
	page := vo.AdminOrderPage{
		PageResult: vo.PageResult{
			TotalCount: total,
			PageSize:   pageDTO.Limit,
			TotalPage:  total / pageDTO.Limit,
			CurrPage:   pageDTO.Page,
		},
		List: orders,
	}
	return page
}

//获取分页数据集
func (receiver MallOrderRepo) findOrdersPage(pageDTO dto.OrderPageDTO) []model.Order {
	var orders []model.Order
	tx := receiver.DB
	if pageDTO.OrderNO != "" {
		tx = tx.Where("order_no = ?", pageDTO.OrderNO)
	}
	if pageDTO.OrderStatus != -1 {
		tx = tx.Where("order_status = ?", pageDTO.OrderStatus)
	}
	tx.Order("create_time desc").Limit(pageDTO.Limit).Offset(pageDTO.Start).Find(&orders)
	return orders
}

//获取订单总记录数
func (receiver MallOrderRepo) findTotal(pageDTO dto.OrderPageDTO) int {
	var total int
	tx := receiver.DB.Model(&model.Order{})
	if pageDTO.OrderNO != "" {
		tx = tx.Where("order_no = ?", pageDTO.OrderNO)
	}
	if pageDTO.OrderStatus != -1 {
		tx = tx.Where("order_status = ?", pageDTO.OrderStatus)
	}
	tx.Count(&total)
	return total
}

func (receiver MallOrderRepo) GetOrderDetailByOrderId(id int) vo.NewBeeMallOrderDetailVO {
	//根据主键查询订单详情
	var order model.Order
	receiver.DB.First(&order, id)
	if order.OrderId == 0 {
		panic("数据不存在")
	}
	//根据订单id查询订单项
	var orderItems []model.OrderItem
	receiver.DB.Where("order_id = ?", order.OrderId).Find(&orderItems)
	if len(orderItems) != 0 {
		//拷贝成vo数据
		var newBeeMallOrderItemVOS []vo.NewBeeMallOrderItemVO
		for _, item := range orderItems {
			orderItemVO := vo.NewBeeMallOrderItemVO{
				GoodsId:       int(item.GoodsId),
				GoodsCount:    int(item.GoodsCount),
				GoodsName:     item.GoodsName,
				GoodsCoverImg: item.GoodsCoverImg,
				SellingPrice:  int(item.SellingPrice),
			}
			newBeeMallOrderItemVOS = append(newBeeMallOrderItemVOS, orderItemVO)
		}
		orderDetailVO := vo.NewBeeMallOrderDetailVO{
			OrderNo:                order.OrderNo,
			TotalPrice:             order.TotalPrice,
			PayStatus:              byte(order.PayStatus),
			PayType:                order.PayType,
			PayTypeString:          util.GetPayTypeEnumByType(order.PayType),
			PayTime:                order.PayTime,
			OrderStatus:            order.OrderStatus,
			OrderStatusString:      util.GetNewBeeMallOrderStatusEnumByStatus(order.PayStatus),
			CreateTime:             order.CreateTime,
			NewBeeMallOrderItemVOS: newBeeMallOrderItemVOS,
		}
		return orderDetailVO
	}
	panic("数据不存在")
}

// CheckOrders 可用于批量执行配货、出库、关闭订单
//tips -> 这里参数列表的 orderStatus 作为三个函数修改状态的值 + 标识符
func (receiver MallOrderRepo) CheckOrders(ids dto.BatchIdParam, orderStatus int) string {
	//查询所有订单 判断状态 修改状态和修改时间
	var orders []model.Order
	receiver.DB.Where("order_id in (" + util.Convert(ids.UserIds) + ")").Find(&orders)
	var errorOrderNosBuf bytes.Buffer
	//这里为了错误信息更详细一些，单独拎出来写
	if len(orders) != 0 {
		for _, order := range orders {
			if order.IsDeleted == 1 {
				errorOrderNosBuf.WriteString(order.OrderNo)
				errorOrderNosBuf.WriteString(" ")
				continue
			}
			//这里用switch筛选一下做哪个操作
			chooseOrderStatus(order, &errorOrderNosBuf, orderStatus)
		}
		//判断errorOrderNos中是否有错误订单
		errorOrderNos := errorOrderNosBuf.String()
		//这里说明没有错误订单
		if len(errorOrderNos) == 0 {
			//执行配货操作
			if err := receiver.DB.Model(&model.Order{}).Where("order_id in (" + util.Convert(ids.UserIds) + ")").
				Update(model.Order{OrderStatus: orderStatus, UpdateTime: model.Time(time.Now())}).Error; err != nil {
				panic("操作失败")
			}
			return "Success"
		}
		//有错误订单
		if len(errorOrderNos) > 0 && len(errorOrderNos) < 100 {
			return errorOrderNos + "订单的状态有误，无法执行操作"
		} else {
			return "错误订单过多！"
		}
	}
	//这里没有查询到返回数据不存在
	panic("数据不存在")
}

//筛选使用哪个函数
func chooseOrderStatus(order model.Order, errorOrderNosBuf *bytes.Buffer, status int) {
	switch status {
	case -3:
		closeOrder(order, errorOrderNosBuf)
	case 3:
		outOrder(order, errorOrderNosBuf)
	case 2:
		doneOrder(order, errorOrderNosBuf)
	}
}

//由于这三块逻辑大部分相同，所有就将部分细节抽出
func doneOrder(order model.Order, errorOrderNosBuf *bytes.Buffer) {
	if order.OrderStatus != 1 {
		errorOrderNosBuf.WriteString(order.OrderNo)
		errorOrderNosBuf.WriteString(" ")
	}
}

func outOrder(order model.Order, errorOrderNosBuf *bytes.Buffer) {
	if order.OrderStatus != 1 && order.OrderStatus != 2 {
		errorOrderNosBuf.WriteString(order.OrderNo)
		errorOrderNosBuf.WriteString(" ")
	}
}

func closeOrder(order model.Order, errorOrderNosBuf *bytes.Buffer) {
	if order.OrderStatus == 4 || order.OrderStatus < 0 {
		errorOrderNosBuf.WriteString(order.OrderNo)
		errorOrderNosBuf.WriteString(" ")
	}
}
